package org.redmagic.service;

import java.util.List;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.rules.ExpectedException;
import org.mockito.Mockito;
import org.redmagic.service.utils.JsonUtils;
import org.redmagic.service.utils.MongoProperties;
import org.redmagic.service.utils.MongoUtils;

import com.google.common.collect.Lists;
import com.mongodb.BasicDBObject;
import com.mongodb.DB;
import com.mongodb.DBCollection;
import com.mongodb.DBObject;
import com.mongodb.Mongo;

public abstract class AbstractMongoDbBackedTestCase {

	protected static final String USER_PROPERTY = "database/user";
	protected static final String PASSWORD_PROPERTY= "database/password";
	protected static final String HOST_PROPERTY = "database/host";
	protected static final String HOSTNAME_PROPERTY = "hostname";
	protected static final String DOMAIN_PROPERTY = "domain";
	
	protected static final String SYSTEM_TYPE_TAG = "systemType=production";
	protected static final String RELEASE_TAG = "release=1.0";
	protected static final String LOCALHOST_TAG = "localhost";
	
	protected static final String USER_VALUE = "test_user";
	
	protected static final List<String> LOCAL_RELEASE_SYSTEM_TAGS = Lists.newArrayList(SYSTEM_TYPE_TAG, LOCALHOST_TAG, RELEASE_TAG);
	protected static final List<String> RELEASE_SYSTEM_TAGS = Lists.newArrayList(SYSTEM_TYPE_TAG, RELEASE_TAG);
	protected static final List<String> RELEASE_TAGS = Lists.newArrayList(RELEASE_TAG);
	protected static final List<String> NO_TAGS = Lists.newArrayList();
	
	@Rule
	public ExpectedException expectedException = ExpectedException.none();
	
	protected Mongo mongo;
	protected DB db;
	protected DBCollection collection;
	protected DBObject fields;
	
	@Before
	public void setUp() {
		
		this.mongo = Mockito.mock(Mongo.class);
		this.db = Mockito.mock(DB.class);
		this.collection = Mockito.mock(DBCollection.class);
		
		Mockito.when(mongo.getDB("test")).thenReturn(db);
		Mockito.when(db.getCollection("test")).thenReturn(collection);
		
		this.fields = new BasicDBObject(MongoProperties.ID, 0);
		this.fields.put(MongoProperties.VALUE_KEY, 1);
	}
	
	@After
	public void tearDown() {
		
		this.collection = null;
		this.db = null;
		this.mongo = null;
	}
	
	protected void mockQuery(String base, List<String> tags, String value) {
		DBObject query = MongoUtils.getQuery(base, tags);
		Mockito.when(collection.findOne(query, fields)).thenReturn(new BasicDBObject(MongoProperties.VALUE_KEY, value));
	}
	
	protected JSONObject getFullRequest() throws JSONException {
		
		JSONArray permutation01 = JsonUtils.toJsonArray(LOCAL_RELEASE_SYSTEM_TAGS);
		JSONArray permutation02 = JsonUtils.toJsonArray(RELEASE_SYSTEM_TAGS);
		JSONArray permutation03 = JsonUtils.toJsonArray(RELEASE_TAGS);
		
		JSONArray hierarchy = JsonUtils.toNestedJsonArray(permutation01, permutation02, permutation03);		
		JSONArray properties = JsonUtils.toJsonArray(USER_PROPERTY, PASSWORD_PROPERTY, HOST_PROPERTY);
		
		return toJsonObject(hierarchy, properties);
	}
	
	protected JSONObject getPartialRequest() throws JSONException {
		
		JSONArray permutation = JsonUtils.toJsonArray(RELEASE_TAGS);
		
		JSONArray hierarchy = JsonUtils.toNestedJsonArray(permutation);
		JSONArray properties = JsonUtils.toJsonArray(HOST_PROPERTY);
		
		return toJsonObject(hierarchy, properties);
	}
	
	private JSONObject toJsonObject(JSONArray hierarchy, JSONArray properties) throws JSONException {
		JSONObject request = new JSONObject();
		request.put(MongoProperties.HIERARCHY_KEY, hierarchy);
		request.put(MongoProperties.PROPERTIES_KEY, properties);
		return request;
	}
}
